`timescale 1ns/1ps
   
module key_table_tb;

    // 参数
    parameter SM2_KEY_NUM = 5;
    parameter SM4_KEY_NUM = 5;
    parameter MAX_KEY_NUM = (SM2_KEY_NUM > SM4_KEY_NUM) ? SM2_KEY_NUM : SM4_KEY_NUM;
    parameter KEY_INDEX_WIDTH = $clog2(MAX_KEY_NUM);

    // 信号定义
    reg                  clk;
    reg                  rst_n;
    reg   [1:0]          mode;
    reg   [1:0]          key_type;
    reg   [KEY_INDEX_WIDTH-1:0] key_index;
    reg   [63:0]         pin;
    reg   [255:0]        key_1_in;
    reg   [255:0]        key_2_in;
    reg   [255:0]        key_3_in;
    reg                  in_valid;

    wire  [255:0]        key_1;
    wire  [255:0]        key_2;
    wire  [255:0]        key_3;
    wire                 key_ready;
    wire  [1:0]          state;

    // 实例化
    key_table #(
        .SM2_KEY_NUM(SM2_KEY_NUM),
        .SM4_KEY_NUM(SM4_KEY_NUM)
    ) dut (
        .clk(clk),
        .rst_n(rst_n),
        .mode(mode),
        .key_type(key_type),
        .key_index(key_index),
        .pin(pin),
        .key_1_in(key_1_in),
        .key_2_in(key_2_in),
        .key_3_in(key_3_in),
        .in_valid(in_valid),
        .key_1(key_1),
        .key_2(key_2),
        .key_3(key_3),
        .key_ready(key_ready),
        .state(state)
    );

    // 时钟生成
    initial clk = 0;
    always #5 clk = ~clk;

    // 产生单周期脉冲信号的任务
    task pulse_valid;
        begin
            in_valid = 1;
            #10;
            in_valid = 0;
            #10;
        end
    endtask

    // 仿真流程
    initial begin
        // 初始化信号
        rst_n = 0;
        mode = 0;
        key_type = 0;
        key_index = 0;
        pin = 0;
        key_1_in = 0;
        key_2_in = 0;
        key_3_in = 0;
        in_valid = 0;
        
        // 复位
        #20;
        rst_n = 1;
        #20;

        // ========== 测试用例1: 写入SM2密钥 ==========
        $display("=== Test Case 1: Write SM2 Key ===");
        mode = 2'b01; // 写模式
        key_type = 2'b00; // SM2
        key_index = 0;
        pin = 64'h12345678;
        key_1_in = 256'hAABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899; // 公钥X
        key_2_in = 256'h00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF; // 公钥Y
        key_3_in = 256'h5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A; // 私钥
        pulse_valid();
        
        // ========== 测试用例2: 写入SM4密钥 ==========
        $display("=== Test Case 2: Write SM4 Key ===");
        mode = 2'b01; // 写模式
        key_type = 2'b01; // SM4
        key_index = 0;
        pin = 64'h87654321;
        key_1_in = {128'd0, 128'hA1B2C3D4E5F60718A9BACBDCEDFE0F10}; // SM4密钥(低128位)
        key_2_in = 0;
        key_3_in = 0;
        pulse_valid();
        
        // ========== 测试用例3: 读取SM2密钥(PIN正确) ==========
        $display("=== Test Case 3: Read SM2 Key (Correct PIN) ===");
        mode = 2'b00; // 读模式
        key_type = 2'b00; // SM2
        key_index = 0;
        pin = 64'h12345678;
        pulse_valid();
        
        // ========== 测试用例4: 读取SM2密钥(PIN错误) ==========
        $display("=== Test Case 4: Read SM2 Key (Wrong PIN) ===");
        mode = 2'b00; // 读模式
        key_type = 2'b00; // SM2
        key_index = 0;
        pin = 64'hDEADBEEF; // 错误PIN
        pulse_valid();
        
        // ========== 测试用例5: 读取SM4密钥(PIN正确) ==========
        $display("=== Test Case 5: Read SM4 Key (Correct PIN) ===");
        mode = 2'b00; // 读模式
        key_type = 2'b01; // SM4
        key_index = 0;
        pin = 64'h87654321;
        pulse_valid();
        
        // ========== 测试用例6: 读取SM4密钥(PIN错误) ==========
        $display("=== Test Case 6: Read SM4 Key (Wrong PIN) ===");
        mode = 2'b00; // 读模式
        key_type = 2'b01; // SM4
        key_index = 0;
        pin = 64'hDEADBEEF; // 错误PIN
        pulse_valid();
        
        // ========== 测试用例7: 非法索引读取 ==========
        $display("=== Test Case 7: Read with Invalid Index ===");
        mode = 2'b00; // 读模式
        key_type = 2'b00; // SM2
        key_index = 5; // 超过范围
        pin = 64'h12345678;
        pulse_valid();
        
        // ========== 测试用例8: 删除SM2密钥 ==========
        $display("=== Test Case 8: Delete SM2 Key ===");
        mode = 2'b10; // 删除模式
        key_type = 2'b00; // SM2
        key_index = 0;
        pin = 64'h12345678;
        pulse_valid();
        
        // ========== 测试用例9: 释放权限 ==========
        $display("=== Test Case 9: Release Permission ===");
        mode = 2'b11; // 释放权限模式
        key_type = 2'b00; // SM2
        key_index = 0;
        pin = 64'h00000000; // 不需要正确PIN
        pulse_valid();
        
        // ========== 测试用例10: 写入已存在位置 ==========
        $display("=== Test Case 10: Write to Occupied Slot ===");
        // 先写入一个密钥
        mode = 2'b01; // 写模式
        key_type = 2'b00; // SM2
        key_index = 1;
        pin = 64'h11111111;
        key_1_in = 256'h1111111111111111111111111111111111111111111111111111111111111111;
        key_2_in = 256'h2222222222222222222222222222222222222222222222222222222222222222;
        key_3_in = 256'h3333333333333333333333333333333333333333333333333333333333333333;
        pulse_valid();
        
        // 尝试写入相同位置
        mode = 2'b01; // 写模式
        key_type = 2'b00; // SM2
        key_index = 1;
        pin = 64'h99999999;
        key_1_in = 256'hAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA;
        key_2_in = 256'hBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB;
        key_3_in = 256'hCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC;
        pulse_valid();
        
        // 结束仿真
        #100;
        $display("=== Simulation Complete ===");
        $finish;
    end

    // 输出波形
    initial begin
        $dumpfile("key_table_tb.vcd");
        $dumpvars(0, key_table_tb);
    end
   
endmodule
